//
// Created by whg on 2025-06-18.
//

#include "functionObject.hpp"
#include "global.hpp"

FunctionKlass* FunctionKlass::instance = nullptr;
FunctionKlass* FunctionKlass::getInstance() {
    if(instance == nullptr){
        instance = new FunctionKlass();
    }
    return instance;
}

void FunctionKlass::print(PyObject* obj) {
    FunctionObject* funcObj = static_cast<FunctionObject*>(obj);
    // FunctionObject* funcObj = (FunctionObject*)obj;
    assert(funcObj->klass() == this);
    printf("<function : ");
    funcObj->funcName()->print();
    printf(">");
}

FunctionObject::FunctionObject(PyObject* codeObj) {
    CodeObject* code = (CodeObject*)codeObj;
    _funcCode = code;
    _funcName = code->_moduleName;
    setKlass(FunctionKlass::getInstance());
}

void FunctionObject::setDefaults(ObjList defaults) {
    if(defaults == nullptr){
        _defaults = nullptr;
        return;
    }

    int defaultsLength = defaults->length();
    _defaults = new ArrayList<PyObject*>(defaultsLength);
    for(int i=0;i<defaultsLength;i++){
        _defaults->set(i, defaults->get(i));
    }
}

PyObject *FunctionObject::call(ObjList args) {
    return (*_nativeFunc)(args);
}

NativeFunctionKlass* NativeFunctionKlass::instance = nullptr;
NativeFunctionKlass* NativeFunctionKlass::getInstance() {
    if(instance == nullptr){
        instance = new NativeFunctionKlass();
    }
    return instance;
}
NativeFunctionKlass::NativeFunctionKlass(){
    setSuper(FunctionKlass::getInstance());
}

PyObject* len(ObjList args){
    return args->get(0)->len();
}

PyObject* print(ObjList args){
    for(int i=0;i<args->length();i++){
        if(i>0){
            printf(" ");
        }
        args->get(i)->print();
    }
    printf("\n");
    return Global::PyNone;
}

MethodKlass* MethodKlass::instance = nullptr;
MethodKlass* MethodKlass::getInstance() {
    if(instance == nullptr){
        instance = new MethodKlass();
    }
    return instance;
}
MethodKlass::MethodKlass(){
    setDict(new PyDict());
    setSuper(FunctionKlass::getInstance());
}

bool MethodObject::isFunction(PyObject* obj) {
    Klass* klass = obj->klass();
    if(klass == FunctionKlass::getInstance()){
        return true;
    }

    klass = klass->super();
    while(klass != nullptr){
        if(klass == FunctionKlass::getInstance()){
            return true;
        }
        klass = klass->super();
    }

    return false;
}

bool MethodObject::isMethod(PyObject* obj) {
    return obj->klass() == MethodKlass::getInstance();
}